#include "stdafx.h"
#include "Console.h"

SmartPtr <System_Console> g_pSystem_Console;

Console_Subscriber :: Console_Subscriber(const std :: string & Identify)
:Identifier(Identify)
{
	IsSubscribed = g_pSystem_Console->Subscribe(this);
}

Console_Subscriber :: ~Console_Subscriber()
{
	IsSubscribed = !g_pSystem_Console->UnSubscribe(this);
}

void Console_Subscriber :: Parse(const std :: string & Input)
{
	Input;
}

System_Console :: System_Console(float Width, float Height)
{
	Font = SmartPtr<hgeFont>(g_pSystem_Main->RESOURCE()->GetFont("TextFont"));
	Font->SetScale(0.7f);
	Font->SetColor(ARGB(255, 255, 255, 255));
	Font->SetBlendMode(BLEND_DEFAULT);

	InputPosition	= Vector2D(-Width * 0.48f, -30);
	OutputPosition	= Vector2D(-Width * 0.48f, -50);
	Position		= Vector2D(Width * 0.5f, 0);

	FullScreenQuad.v[0].x = -Width * 0.5f; 
	FullScreenQuad.v[0].y = -Height * 0.5f; 
	FullScreenQuad.v[1].x = Width * 0.5f; 
	FullScreenQuad.v[1].y = -Height * 0.5f; 
	FullScreenQuad.v[2].x = Width * 0.5f; 
	FullScreenQuad.v[2].y = 0; 
	FullScreenQuad.v[3].x = -Width * 0.5f; 
	FullScreenQuad.v[3].y = 0; 
	FullScreenQuad.v[0].z = 1.0f; 
	FullScreenQuad.v[1].z = 1.0f; 
	FullScreenQuad.v[2].z = 1.0f; 
	FullScreenQuad.v[3].z = 1.0f; 

	FullScreenQuad.blend = BLEND_DEFAULT_Z;
	FullScreenQuad.tex = 0;
	for (int i = 0; i < 4; i++) 
		FullScreenQuad.v[i].col = ARGB(120, 0, 0, 0 ); 
}

System_Console :: ~System_Console()
{
	Font.release();
}

bool System_Console :: Subscribe(Console_Subscriber * Address)
{
	std::map <std::string, Console_Subscriber *> :: iterator it = mSubscribers.find(Address->Identity());
	if(it != mSubscribers.end()) return false;
	// If not found, subscribe this address
	std::pair<std::string, Console_Subscriber *> Pair;
	Pair.first = Address->Identity();
	Pair.second = Address;
	mSubscribers.insert(mSubscribers.end(), Pair);
	return true;
}

bool System_Console :: UnSubscribe(Console_Subscriber * Address)
{
	std::map <std::string, Console_Subscriber *> :: iterator it = mSubscribers.find(Address->Identity());
	if(it != mSubscribers.end()) return false;
	// if found, remove from subscribtion.
	mSubscribers.erase(it);
	return true;
}

void System_Console :: FeedTextLog(std :: string Text)
{
	Text = "Debug : " + Text;
	Log.push_front(Text);
	if(Log.size() > 9)
		Log.pop_back();
}

void System_Console :: OnOffConsole()
{
	mbRender = !mbRender;
}

void System_Console :: ProcessInput()
{
	if(KeyPressed(VK_BACK) && CurrentText.size() > 0)
		CurrentText = CurrentText.substr(0, CurrentText.size() - 1);
	else if(KeyPressed(VK_RETURN))
	{
		ParseCommand();
		if(CurrentText.size() > 0)
			Log.push_front(CurrentText);
		CurrentText.clear();
		if(Log.size() > 9)
			Log.pop_back();
		
	}
	else if(CurrentText.size() > 100) return;

	for(int i = HGEK_A; i < HGEK_Z + 1; i++)
	{
		if(CurrentText.size() > 100) break;
		if(KeyPressed(i))
			if(KeyDown(VK_SHIFT))
				CurrentText += char(i);
			else
				CurrentText += char(i + 32);
	}
	for(int i = 0; i < 10; i++)
	{
		if(CurrentText.size() > 100) break;
		if(KeyPressed(HGEK_0 +i))
			if(KeyDown(VK_SHIFT))
				CurrentText += char(HGEK_0 + i - 16);
			else
				CurrentText += char(HGEK_0 + i);
		else if(KeyPressed(HGEK_NUMPAD0 + i))
			CurrentText += char(HGEK_0 + i);
	}

	if(CurrentText.size() < 101)
	{
		if(KeyPressed(VK_SPACE))
			CurrentText += " ";
		else if(KeyPressed(HGEK_SEMICOLON))
			CurrentText += ";";
		else if(KeyPressed(HGEK_APOSTROPHE))
		{
			if(KeyDown(VK_SHIFT))
				CurrentText += char(34);
			else
				CurrentText += "'";
		}
		else if(KeyPressed(HGEK_COMMA))
			CurrentText += ",";			
		else if(KeyPressed(HGEK_PERIOD) || KeyPressed(VK_DECIMAL))
			CurrentText += ".";
		else if(KeyPressed(HGEK_SLASH))
			CurrentText += "/";
		else if(KeyPressed(VK_ADD) || (KeyPressed(HGEK_EQUALS) && KeyDown(VK_SHIFT)))
			CurrentText += "+";
		else if(KeyPressed(VK_SUBTRACT))
			CurrentText += "-";
		else if(KeyPressed(VK_MULTIPLY))
			CurrentText += "*";
		else if(KeyPressed(VK_DIVIDE))
			CurrentText += "/";
		else if(KeyPressed(HGEK_EQUALS))
			CurrentText += "=";
		else if(KeyPressed(VK_OEM_MINUS))
		{
			if(KeyDown(VK_SHIFT))
				CurrentText += "_";
			else
				CurrentText += "-";
		}
	}
}

void System_Console :: Update(const float & Interval)
{		
	if(mbRender)
		(Position.y > 0)? Position.y -= 500 * Interval : (Position.y < 0)? Position.y = 0.0f : NULL;
	else
		(Position.y < APP_HEIGHT * 0.5f)? Position.y += 500 * Interval : (Position.y > APP_HEIGHT * 0.5f)? Position.y = APP_HEIGHT * 0.5f : NULL;

	if(Position.y != APP_HEIGHT * 0.5f)	
		return;
	else
		ProcessInput();
}

void System_Console :: ParseCommand()
{
	std::string Buffer, Buffer2;
	size_t i = 0;
	if(CurrentText.size() < 1)
	{
		FeedTextLog("Invalid Syntax");
		return;
	}
	for(; i < CurrentText.size(); i++)
		if(CurrentText[i] == 32)
			break;
		else
			Buffer.push_back(CurrentText[i]);
	Buffer = Buffer.c_str();
	if(i == CurrentText.size())
	{
		FeedTextLog("Invalid Syntax");
		return;
	}
	Buffer2 = CurrentText.substr(i + 1, CurrentText.size());
	std::map <std::string, Console_Subscriber *>::iterator it = mSubscribers.find(Buffer);
	if(it == mSubscribers.end())
	{
		FeedTextLog("Invalid Syntax");
		return;
	}
	try
	{
		it->second->Parse(Buffer2);
	}
	catch(...)
	{
		WriteCommandLine("Exception Occured Parsing %s", it->first.c_str());
	}
}

void System_Console :: Render()
{
	// Move to
	g_pSystem_Main->HGESYSTEM()->Gfx_SetTransform(0, 0, Position.x, Position.y, 0, 1, 1);
	g_pSystem_Main->HGESYSTEM()->Gfx_RenderQuad(&FullScreenQuad);

	std :: string Text = "Input : " + CurrentText;
	Font->Render(InputPosition.x, InputPosition.y, HGETEXT_LEFT, Text.c_str());

	for(size_t i = 0; i < Log.size(); i++)
	{
		Text =	">>>> " + Log[i];
		Font->Render(OutputPosition.x, OutputPosition.y - i * 20, HGETEXT_LEFT, &Text[0]);
	}
	// Reset Transform to prev
	g_pSystem_Main->HGESYSTEM()->Gfx_SetTransform(0, 0,APP_WIDTH >> 1, APP_HEIGHT >> 1, 0, 1, 1);
}